#!/usr/bin/perl -w

#---------------------------------------------------------------------
#
# this script works with the generation.mak makefile fragment and is
# concerned with generation of make files and other standard files
# from templates. It is based on work done by Rod Whitby and others at
# Austek Microsystems in 1991 and has been extended and rewritten my
# Thomas Dejanovic over the years since then.
#
# $Copyright: (c) 1997-2008 Thomas Dejanovic $ 
#
#---------------------------------------------------------------------

use FileHandle;
use Carp;
use Getopt::Long;

#---------------------------------------------------------------------
#
# suck in the template verilog module from the PROJ_TEMPLATES
# directory, changing the generic module name to the name specified on
# the command line.
#

sub module_template {
    my(%flag_hash) = @_;

    # look for a .v extension to make sure we dont make *.v.v files.
    my $module_name = $flag_hash{'module_name'};
    $module_name =~ s/\.v$//;

    my $template_file_name = "";
    my $module_file_name   = "";
    
    if ($module_name =~ /^(\w+)_test$/) {
        $module_name = $1;
        $template_file_name = $ENV{TOOL_DIR} . "/templates/module_test_template.v";
        $module_file_name   = $module_name . "_test.v";
    } else { 
        $template_file_name = $ENV{TOOL_DIR} . "/templates/module_template.v";
        $module_file_name   = $module_name . ".v";
    }
    
    my $module_test_name = $module_name . "_test";

    my($fh_in) = new FileHandle;
    if (!$fh_in->open("< $template_file_name")) {
        print "*** ERROR - could not find template file $template_file_name.\n" ;
       exit 1;
    }

    if (-e $module_file_name) {
        print "*** ERROR - $module_file_name already exists.\n" ;
        $fh_in->close();
        exit 1;
    }

    my($fh_out) = new FileHandle;
    if (!$fh_out->open("> $module_file_name")) {
        print "*** ERROR - Could not write module file $module_file_name.\n" ;
        $fh_in->close();
        exit 1;
    } 

    my $line;
    while ($line = $fh_in->getline) {
        # look for the module name and change it.
        if ($line =~ /^(.*\s*)MODULE_NAME(\s*.*)$/) {
            $line = "$1$module_name$2\n";
        }
        if ($line =~ /^(.*\s*)MODULE_TEST_NAME(\s*.*)$/) {
            $line = "$1$module_test_name$2\n";
        }
        $fh_out->print($line);
    }

    $fh_out->close();
    $fh_in->close();
}
    
#---------------------------------------------------------------------

sub makefile_template {
    my(%flag_hash) = @_;

    my $template_file_name = $ENV{TOOL_DIR} . "/templates/makefile_template";
    
    my($fh_in) = new FileHandle;
    if (!$fh_in->open("< $template_file_name")) {
        print "*** ERROR - could not find template file $template_file_name.\n" ;
        exit 1;
    }

    my($fh_out) = new FileHandle;
    if (!$fh_out->open("> Makefile")) {
        print "*** ERROR - Could not write Makefile.\n" ;
        exit 1;
    } 

    my $proj_dir = $ENV{PROJ_DIR};

    # if the module name is found in the list of property directories,
    # the module name is changed to the name one level up in the path.
    my @properties = ('rtl', 'syn', 'par', 'etc', 'doc', 'wrapper');

    my $module = "";
    my $path = "";

    if (exists($flag_hash{'module'})) {
        $module = $flag_hash{'module'};
    }

    if (exists($flag_hash{'path'})) {
        $path = $flag_hash{'path'};
    }

    if (($module eq "") && ($path ne "")) {
        # module name not defined, so infer it from the path.
        my @p = split(/\//, $flag_hash{'path'});
        $module = $p[$#p];
    } else {
        # this is a special case where we are at the top of the
        # project tree. or maybe we are building a new makefile.
        $path = `pwd`;
        $path =~ s/\n//;
        my @p = split(/\//, $path);
        $module = $p[$#p];
    }

    if ((grep(/$module/, @properties) > 0) && ($path ne "")) {
        # this is a proper sub directory.
        my @p = split(/\//, $path);
        $module = $p[$#p - 1];
    }

    my $line;
    while ($line = $fh_in->getline) {

        if ($line =~ /^\#\s+include\s+.*\/+(\w+).mak\s*$/) {
            # look for comented out include lines.  if a flag matching
            # the file name is set then uncomment the line.

            if ($flag_hash{$1} == 1) {
                $line =~ s/^\#\s*//g;
            }
        } elsif ($line =~ /^\#\s+include\s+.*\.(p\w+pend)\s*$/) {
            # look for the makefile pre and post pend lines.
            if (defined($flag_hash{$1})) {
                if ($flag_hash{$1} == 1) {
                    $line =~ s/^\#\s*//g;
                }
            } else {
                print "*** ERROR we have a problem with line :", $line;
                $fh_in->close();
                exit 1;
            }

        } elsif ($line =~ /^MODULE = /) {
            # process the module name line.
            $line = "MODULE = $module\n";
        } elsif ($line =~ /^MODULE_PATH = /) {
            # process the module name line.
            $line = "MODULE_PATH = $path\n";
        } elsif ($line =~ /^LOCAL_SOURCE_FILES = /) {
            # process  list
            my $s = join(' ', @{$flag_hash{'source_file_list'}});
            $s =~ s/  / /g;
            $line = "LOCAL_SOURCE_FILES = $s\n";
        } elsif ($line =~ /^SUBMODULES = /) {
            # process  list
            my $s = join(' ', @{$flag_hash{'submodule_list'}});
            $s =~ s/  / /g;
            $line = "SUBMODULES = $s\n";
        } elsif ($line =~ /^([A-Z_]+)(\s+)=\s*/) {
            my $uc_var_name = $1;
            my $spaces = $2;
            my $lc_var_name = $uc_var_name;
            $lc_var_name =~ tr/[A-Z]/[a-z]/;
            $lc_var_name =~ s/_dirs$/_dir_list/;
            $lc_var_name =~ s/_files$/_file_list/;
            # process the directory / file list
            my @list = ();
            foreach my $e (@{$flag_hash{$lc_var_name}}) { 
                $e =~ s/\s+/ /g;
                $e =~ s/^\s+//g;
                $e =~ s/\s+$//g;
                push(@list, split(/ /, $e));
            }
            my $l = "$uc_var_name$spaces=";
            my $pad_len = length($l);
            my $pad_string = " \\\n". " " x ($pad_len);
            $line = "";
            foreach my $e (@list) {
                $e =~ s/\s*//g;
                $e =~ s/$proj_dir/\$\{PROJ_DIR\}/;
                if ((length($l) != length($pad_string)) || (length($l) != $pad_len)){
                    # line is not empty
                    if (length($l." ".$e) > 85) {
                        $line = $line . $l;
                        $l = $pad_string . " " . $e;
                    } else {
                        $l = $l." ".$e;
                        if (length($l) > 76) {
                            $line = $line . $l;
                            $l = $pad_string;
                        }
                    }
                }
            }
            if (length($l) == length($pad_string)) {
                $line = $line . "\n";
            } else {
                $line = $line . $l . "\n";
            }
        }

        $fh_out->print($line);
    }

    $fh_out->close();
    $fh_in->close();
 };
    
#---------------------------------------------------------------------
#
# these are the options used ot generate a makefile.
#

my $makefile=0;

my %makefile_hash= ();
$makefile_hash{'module'} = '';
$makefile_hash{'path'} = '';

$makefile_hash{'prepend'}    = 0;
$makefile_hash{'postpend'}   = 0;
$makefile_hash{'xilinx_ise'} = 0;
$makefile_hash{'hatch'}   = 0;
$makefile_hash{'iverilog'}   = 0;

$makefile_hash{'verilog_black_box_dir_list'} = ();
$makefile_hash{'verilog_module_dir_list'} = ();
$makefile_hash{'verilog_library_dir_list'} = ();
$makefile_hash{'verilog_library_file_list'} = ();
$makefile_hash{'verilog_netlist_dir_list'} = ();
$makefile_hash{'source_file_list'} = ();
$makefile_hash{'submodule_list'} = ();
 
#
# these are the options used to generate an empty verilog file.
#

my $module_template=0;
my %module_template_hash= ('module_name' => '',
                           );

GetOptions(# makefile options
           'makefile'     => \$makefile,
           'module:s'     => \$makefile_hash{'module'},
           'path:s'       => \$makefile_hash{'path'},
           'prepend=i'    => \$makefile_hash{'prepend'},
           'xilinx_ise=i' => \$makefile_hash{'xilinx_ise'},
           'hatch=i'      => \$makefile_hash{'hatch'},
           'iverilog=i'   => \$makefile_hash{'iverilog'},
           'postpend=i'   => \$makefile_hash{'postpend'},
           'verilog_module_dirs:s'      => \@{$makefile_hash{'verilog_module_dir_list'}},
           'verilog_library_dirs:s'     => \@{$makefile_hash{'verilog_library_dir_list'}},
           'verilog_library_files:s'    => \@{$makefile_hash{'verilog_library_file_list'}},
           'verilog_netlist_dirs:s'     => \@{$makefile_hash{'verilog_netlist_dir_list'}},
           'verilog_black_box_dirs:s'   => \@{$makefile_hash{'verilog_black_box_dir_list'}},
           'source_file|source_files:s' => \@{$makefile_hash{'source_file_list'}},
           'submodule|submodules:s'     => \@{$makefile_hash{'submodule_list'}},

           # module options
           'module_template'=> \$module_template,
           'module_name=s'  => \$module_template_hash{'module_name'},
           );

if ($makefile == 1) {
    &makefile_template(%makefile_hash);
} elsif ($module_template == 1) {
    &module_template(%module_template_hash);
} else {
    print "No file type to generate specified, use --makefile or --module_template.\n";
}


#---------------------------------------------------------------------
# Local Variables:
# mode: perl
# End:
